package com.fangcun.filter;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import com.fangcun.bean.admin.user.response.LoginResponse;
import com.fangcun.bean.sys.ResponseMsg;
import com.fangcun.common.auth.UserAuthMethod;
import com.fangcun.common.canstant.ErrCode;
import com.fangcun.common.canstant.PublicConstant;
import com.fangcun.common.exception.ProException;
import com.fangcun.common.exception.ProValiDataException;
import com.fangcun.common.util.PublicMethod;
import com.fangcun.common.util.json.JSONTools;
import com.fangcun.entity.SysInterfaceRule;
import com.fangcun.service.SystemService;

/**
 * @作者： 陳曉鬆 @时间： 2018年5月17日 - 下午3:49:12 @description：->
 */
@Component
public class SecurityFilter implements HandlerInterceptor {

	private static Logger LOG = LoggerFactory.getLogger(SecurityFilter.class);

	@Resource(name = "systemService")
	private SystemService systemService;

	// 不需要验证访问的的接口
	public static List<String> noFilterUrl = null;
	static {
		noFilterUrl = new ArrayList<String>();
		noFilterUrl.add("/sys/v1.0/pay/wx/notify"); // 微信支付回调过滤
		noFilterUrl.add("/sys/v1.0/pay/alipay/notify");// 支付宝支付回调过滤
	}

	/**
	 * controller 执行之前调用
	 */
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
		String ip = PublicMethod.getIp(request);
		try {
			String url = request.getRequestURI();

			// 不需要验证访问的的接口
			if (noFilterUrl.contains(url)) {
				return true;
			}

			if (!ip.contains("0:0:0:0:0:0:0:1") && !ip.contains("127.0.0.1")) {
				verificationCipherText(request, systemService);
			} else {
				String method = request.getMethod();
				LOG.info("---Method-->" + method + "---IP-->" + ip + "---url-->" + url);
			}

			String token = request.getHeader(UserAuthMethod.LOGIN_TOKEN_NAME);

			// 刷新登录token
			String loginValue = systemService.refreshLoginToken(token);
			// 验证访问链接是否要判断登录
			if (url.contains("/auth/") || url.contains("\\auth\\")) {
				systemService.verificationLoginToken(token, url, loginValue);
			}
			// 判断后台权限
			if (!StringUtils.isEmpty(loginValue)) {
				LoginResponse adminLogin = JSONTools.jsonStr2obj(loginValue, LoginResponse.class);
				if (adminLogin != null && !StringUtils.isEmpty(adminLogin.getPassWord())) {
					if (!PublicConstant.BACK_SUPER_ACCOUNT.equals(adminLogin.getUserName())
							&& (adminLogin.getUserPermissionUrl() == null || !adminLogin.getUserPermissionUrl().contains(url))) {
						throw new ProValiDataException(ErrCode.USER_URL_NO_REQUEST.getReturnCode(), ErrCode.USER_URL_NO_REQUEST.getReturnMsg());
					}
				}
			}
		} catch (ProException e) {
			ResponseMsg msg = ResponseMsg.returnBeanBuild().setReturnCode(e.getErrorCode()).setReturnMsg(e.getErrorMsg());
			PublicMethod.outPrint(response, JSONTools.obj2json(msg), "json");
			LOG.error("-访问过滤-出错:appKey:{},{},{}", request.getHeader("appkey") + "->" + ip, e.getErrorCode(), e.getErrorMsg());
			return false;
		} catch (Exception e) {
			ResponseMsg msg = ResponseMsg.returnBeanBuild().setReturnCode(ErrCode.ERR.getReturnCode()).setReturnMsg(ErrCode.ERR.getReturnMsg());
			PublicMethod.outPrint(response, JSONTools.obj2json(msg), "json");
			LOG.error("-访问过滤-异常:appKey:{},{}", request.getHeader("appkey") + "->" + ip, PublicMethod.printErrorTrace(e));
			return false;
		}
		return true;
	}

	/**
	 * controller 执行之后，且页面渲染之前调用
	 */
	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
		// System.out.println(111111111111L);
	}

	/**
	 * 页面渲染之后调用，一般用于资源清理操作
	 */
	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
		// System.out.println("------afterCompletion-----");
	}

	/**
	 * 
	 * @description：-> 所有接口验证接口访问有效性
	 * 
	 * @param reguest
	 * @return
	 *
	 * @作者：陳曉鬆
	 * @时间：2018年3月15日 上午9:19:37 @版本：V1.0
	 *
	 */
	public static String verificationCipherText(HttpServletRequest request, SystemService systemService) throws ProException {

		String requestUrl = request.getRequestURI();
		String ip = PublicMethod.getIp(request);
		String method = request.getMethod();
		String referer = request.getHeader("referer");

		// 签名(userKey+随机数+安全SECRET+时间戳) md5转换为大写字母 3次加密
		String signature = request.getHeader("signature");
		String appKey = request.getHeader("appkey");// 与SECRET一起得到的key
		String nonce = request.getHeader("nonce");// 随机数
		String timestamp = request.getHeader("timestamp");// 时间戳
		if (StringUtils.isEmpty(appKey)) {
			throw new ProValiDataException(ErrCode.ERR_INVALIDSECRET_NO_EXISTED.getReturnCode(), ErrCode.ERR_INVALIDSECRET_NO_EXISTED.getReturnMsg());
		}

		// 得到secret
		SysInterfaceRule interfaceRule = systemService.getInterfaceRule(appKey);
		if (interfaceRule == null) {
			throw new ProValiDataException(ErrCode.ERR_INVALIDSECRET_NO_EXISTED.getReturnCode(), ErrCode.ERR_INVALIDSECRET_NO_EXISTED.getReturnMsg());
		}

		/** 过滤不需要做验证的地址 */
		if (!StringUtils.isEmpty(interfaceRule.getNoFilterUrl()) && interfaceRule.getNoFilterUrl().contains(requestUrl)) {
			LOG.info("-接口访问验证-appKey：{}-不需要做验证的---Method-->{}---IP-->{}---url-->{}", appKey, method, ip, requestUrl);
			return "200";
		}

		// 验证ip或者referer
		boolean filterIp = false;
		if (!StringUtils.isEmpty(interfaceRule.getFilterIp())) {
			String str[] = interfaceRule.getFilterIp().split(",");
			for (int i = 0; i < str.length; i++) {
				if (str[i].matches(PublicConstant.REQEX_IP)) {// 如果是ip，则验证ip
					if (ip.equals(str[i])) {
						filterIp = true;
						break;
					}
				} else {// 验证referer
					if ((!StringUtils.isEmpty(referer) && referer.contains(str[i]))) {
						filterIp = true;
						break;
					}
				}
			}
		} else {// 如果为null就是不验证
			filterIp = true;
		}
		if (!filterIp) {
			LOG.info("-接口访问验证-appKey：{}-ip或者referer无权访问该服务---Method-->{}---IP-->{}---url-->{}", appKey, method, ip, requestUrl);
			throw new ProValiDataException(ErrCode.ERR_INVALIDSECRET_NO_EXISTED.getReturnCode(), ErrCode.ERR_INVALIDSECRET_NO_EXISTED.getReturnMsg());
		}

		// md5 两次加密 比对
		String str = PublicMethod.getMd5(appKey + nonce + interfaceRule.getSecret() + timestamp, 3, true);
		if (!str.equals(signature)) {
			LOG.error("-接口访问验证-appKey：{}-接口密文验证失败---前端加密密文与后端加密密文不等->{}", appKey, str);
			throw new ProValiDataException(ErrCode.ERR_INVALIDSECRET.getReturnCode(), ErrCode.ERR_INVALIDSECRET.getReturnMsg());
		}
		long chaTime = new Date().getTime() - Long.parseLong(timestamp);
		chaTime = chaTime < 0 ? -chaTime : chaTime;
		if (chaTime > 90000) {// 大于90秒过期
			LOG.error("-接口访问验证-appKey：{}-接口密文验证失败---时间不在0到90之内", appKey);
			throw new ProValiDataException(ErrCode.ERR_INVALIDSECRET.getReturnCode(), ErrCode.ERR_INVALIDSECRET.getReturnMsg());
		}
		return "200";
	}
}
